using System;
using System.Collections.Generic;
using System.Text;

namespace PicoInterface
{
    public class PicoIO
    {
        public const int BASE_ADDR = 184549376;
        public const int IO_ADDR = 184614912;
        public const int IO_STATUS_REG_ADDR = BASE_ADDR + 6;

        public static string Attach(string sImageName)
        {
            string sResult = "";

            StringBuilder buffer = new StringBuilder(1024, 1024);
            if (!PicoInvoke.CreatePicoXface("c:\\pico\\bin\\"))
            {
                return PicoInvoke.GetLastError();
            }

            PicoInvoke.GetCurrentImage(buffer);
            if (buffer.ToString().Length == 0)
                return "Error reading getting pico image file name \n" + PicoInvoke.GetLastError();
            sResult += buffer.ToString() + "\n";

            PicoInvoke.Reboot(sImageName, true);

            if (!PicoInvoke.GetCurrentImage(buffer))
            if (buffer.ToString().Length == 0)
                return "Error reading getting pico image file name \n" + PicoInvoke.GetLastError();
            
            sResult += buffer.ToString() + "\n";
            return sResult;
        }

        public static void Reset()
        {
            PicoInvoke.WriteDevice(BASE_ADDR, 3);
        }

        public static void StopClock()
        {
            PicoInvoke.WriteDevice(BASE_ADDR, 0);
        }

        public static void StartClock()
        {
            //string cyclesBinary = RapidHDL.Conversion.IntToBinaryString(16383, 14) + "01";
            string cyclesBinary = RapidHDL.Conversion.IntToBinaryString(1024, 14) + "01";
            PicoInvoke.WriteDevice(BASE_ADDR, RapidHDL.Conversion.StringBinaryToInt(cyclesBinary));
        }

        public static void StartClock(int cycles)
        {
            int loops = 1;

            if (cycles > 16000)
            {
                loops = cycles / 16000;
                cycles = 1600;
            }

            double secs = cycles / 25.0 / 1000000.0;
            int delay = (int)(secs * 1000);
            delay += 1;

            //JNA modify here if base clock speed changes!
            string cyclesBinary = RapidHDL.Conversion.IntToBinaryString(cycles * 2, 14) + "01";

            for (int loopIdx = 0; loopIdx < loops; loopIdx++)
            {
                PicoInvoke.WriteDevice(BASE_ADDR, RapidHDL.Conversion.StringBinaryToInt(cyclesBinary));
                //System.Threading.Thread.Sleep(delay);
            }
        }

        public static void WriteData(int value)
        {
            string valueBinary = RapidHDL.Conversion.IntToBinaryString(value, 13) + "100";
            PicoInvoke.WriteDevice(BASE_ADDR, RapidHDL.Conversion.StringBinaryToInt(valueBinary));
        }

        public static void StoreAddress(int addr)
        {
            // this loads the address to be used by WriteData
            string valueBinary = RapidHDL.Conversion.IntToBinaryString(addr, 13) + "000";
            PicoInvoke.WriteDevice(BASE_ADDR, RapidHDL.Conversion.StringBinaryToInt(valueBinary));
        }


        public static int Read(int addr)
        {
            string addrBinary = RapidHDL.Conversion.IntToBinaryString(addr, 14) + "10";
            PicoInvoke.WriteDevice(BASE_ADDR, RapidHDL.Conversion.StringBinaryToInt(addrBinary));
            return PicoInvoke.ReadDevice(BASE_ADDR);
        }

        public static int ReadIOStatusReg()
        {
            return PicoInvoke.ReadDevice(IO_STATUS_REG_ADDR);            
        }

        public static void WriteArray(ushort[] data, int length)
        {
            PicoInvoke.WriteDeviceArray(IO_ADDR, data, length);
        }

        public static void ReadArray(ushort[] data, int length)
        {
            PicoInvoke.ReadDeviceArray(IO_ADDR, data, length);            
        }



        /*public static void DisplayAddr(int addr)
        {
            int data = Read(addr);
            string binary = RapidHDL.Conversion.IntToBinaryString(data, 16);
            Console.WriteLine(addr.ToString() + ": " + binary + " {" + data.ToString() + "}");
        }*/
    }
}
